/* NoX (NoC Simulator)
 *
 * Dept. of Computer Science & Engineering, Pennsylvania State University.
 * All Rights Reserved.
 *  
 * 1. License     
 * NoX is distributed free of charge for academic, educational, noncommercial 
 * research purposes as long as this notice in its entirety is preserved in
 * every file included in this package.
 * All commercial use of this program requires separate licence. Contact the
 * author for details.
 * 
 * 2. All the publications that used the simulation results generated by the 
 * NoX should notify the author of the publication information and put 
 * following reference.
 *
 *  http://www.cse.psu.edu/~dpark/nox/
 * 
 * 3. Modification of the source code is permitted and encouraged as long as 
 * it follows the terms described in this copyright notice.
 *
 * 4. The author is not responsible for any problems caused by possible errors
 * of the NoX package. Therefore, users should verify the simulation result
 * before using it in their publication.
 *
 * Dept. of Computer Science & Engineering, Pennsylvania State University.
 * Contact: dpark@cse.psu.edu 
 * 
 * 6. If problems are found with the NoX package, please send an email to the
 * author for discussion and correction.

*/

/* Update History
 *
 * Jan. 31, 2006  Version 1.0 released by Dongkook Park 
 *
 */

/* SIM_INIT.C - Initializes the simulation setting */

#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <zlib.h>

#include "main.h"
#include "router.h"
#include "power.h"
#include "flit.h"
#include "node_marking.h"
#include "route_proximity_aware.h"
#include "shared.h"
#include "batch.h"
#include "rank.h"

#ifdef TR_INTEG
// TR_INTEG begin
#undef INVALID

#include "defines.h"
#include "transaction.h"
#include "globals.h"

#undef INVALID
#define INVALID 1
// TR_INTEG end
#endif


void sim_init(int argc, char **argv)
{
  int node, pc, vc, count;
  char sql_fn[41];
  bool buffer_depth_not_defined=true;

  // Initialize the simulator setting.
  sim_end_flag = INVALID;
  sim_clock         = 0;
  num_inj_msg       = 0;
  num_ejt_msg       = 0;
  num_ejt_flit      = 0;
  num_link_err      = 0;
  num_routing_err   = 0;
  num_swarbiter_err = 0;
  warmup_cycle      = 0;
  num_e2e_nack      = 0;
  num_e2e_retrans   = 0;
  num_escape_msgs   = 0;

  // For the statistics.
  total_packet_delay_cycle        = 0;
  total_delay_cycle        = 0;
  total_latency            = 0;
  total_queueing_latency   = 0;
  total_network_latency    = 0;
  total_aged_flit10        = 0;
  total_aged_flit20        = 0;

  cmsg_total_delay_cycle        = 0;
  cmsg_total_latency            = 0;
  cmsg_total_queueing_latency   = 0;
  cmsg_total_network_latency    = 0;

  dmsg_total_delay_cycle        = 0;
  dmsg_total_latency            = 0;
  dmsg_total_queueing_latency   = 0;
  dmsg_total_network_latency    = 0;

  for(node=0; node<NUM_NODES; node++)
    total_buf_usage[node]  = 0;

  p_buffer                 = 0;
  p_routing                = 0;
  p_vc_arb                 = 0;
  p_sw_arb                 = 0;
  p_xbar                   = 0;
  p_link                   = 0;
  p_err_chk                = 0;
  p_retrans                = 0;


  init_free_list(); // defined in flit.h/c

  // initialize random seed with the last two bytes of the time value.
  // But, enabling below line is not recommended if you're still debugging
  // since data injection will be diffrent for each run making it harder 
  // to track the error.
  // Enable following line if you want to run the simulation with the exactly
  // the same options while expecting different random sequences to get 
  // the average statistics from several runs.
  //
  //srand( (unsigned int)(time(NULL)) & 0xFF );
  //
  // Other wise, use fixed random seed.
  srand(0); // Fixed random seed


  // Now, check for the options given in the command line.
  // Before this, set the default values for each possible options.
  // They might be overwritten by the specified value from the command line.
  routing_algorithm  = DT;
  topology           = MESH;
  load_rate          = 0.25;
  verbose            = NO;
  probe_verbose      = NO;
  retrans_type       = NONE;
  pattern            = NR;
  arch               = 2;
  link_err_rate      = 0.0;
  routing_err_rate   = 0.0;
  swarbiter_err_rate = 0.0;
  in_traffic         = UNIFORM;
  num_failed_link    = 0;
  num_failed_node    = 0;
  sql                = NO;
  early_ejection     = NO;
  MSG_LEN            = 0;

  count=1;
  float link_length=1.0;
  float high_swing_factor=1.0;
  int batching=BATCHING_MODE_NONE, ranking=RANKING_NONE;
  int batch_cap=16;
  long long batch_int=100;
  long long rank_int=100;
  float bursty_rate=0;
  int bursty_nodes[MAX_NODES] = {0};
  int mix_pattern[16];
  int ROB_SIZE=32;
  int cluster_cols,cluster_rows;
  int num_patterns=-1;
  int rank_levels=-1;

  int technode = -1;


  while(count < argc)
  {
    if(strstr(argv[count], "#"))
    {
      printf("\nIgnoring Comment %s\n",argv[count]);
      count++;
    }
    // R represents 'Routing Algorithm'
    else if(!strcmp(argv[count], "-r"))
    {
      printf("%s",argv[count]);
      count++;
      printf("%s",argv[count]);
      if(count == argc) {printf("Not enough parameters\n"); exit(0);}
      else if(!strcmp(argv[count], "DT")) routing_algorithm = DT;
      else if(!strcmp(argv[count], "AD")) routing_algorithm = AD;
      else if(!strcmp(argv[count], "PA")) routing_algorithm = PA;
      else if(!strcmp(argv[count], "SF")) routing_algorithm = SF;
      else if(!strcmp(argv[count], "WF")) routing_algorithm = WF;
      else   {printf("Invalid routing algorithm.\n"); exit(0);}
      count++;
    }

    // T represents 'Topology'
    else if(!strcmp(argv[count], "-t"))
    {
      printf("%s",argv[count]);
      count++;
      printf("%s",argv[count]);
      if(count == argc) {printf("Not enough parameters\n"); exit(0);}
      else if(!strcmp(argv[count], "MESH" )) topology = MESH;
      else if(!strcmp(argv[count], "TORUS")) topology = TORUS;
      else if(!strcmp(argv[count], "BFLY")) topology = BFLY;
      else if(!strcmp(argv[count], "BUS"))   topology = BUS;
      else if(!strcmp(argv[count], "XBAR"))  topology = XBAR;
      else if(!strcmp(argv[count], "FTREE"))  topology = FTREE;
      else if(!strcmp(argv[count], "TTREE"))  topology = TTREE;
      else   {printf("Invalid topology.\n"); exit(0);}
      count++;
    }

    else if(!strcmp(argv[count], "-arb"))
    {
      printf("%s",argv[count]);
      count++;
      printf("%s",argv[count]);
      if(count == argc) {printf("Not enough parameters\n"); exit(0);}
      else if(!strcmp(argv[count], "RR" ))  ARB_TYPE = RR;
      else if(!strcmp(argv[count], "PR" ))  ARB_TYPE = PR;
      else if(!strcmp(argv[count], "AGE" ))  
      {ARB_TYPE = PR; age_based_arbitration=true;}
      else if(!strcmp(argv[count], "SLACK" ))  
      {ARB_TYPE = PR; slack_based_arbitration=true;}
      else if(!strcmp(argv[count], "AgePR" ))  
      {ARB_TYPE = PR; enable_age_PR=true;}
      else if(!strcmp(argv[count], "AppAgePR" ))  
      {ARB_TYPE = PR; enable_age_PR=true; enable_app_age=true;}
      else   {printf("Invalid arbitration type.\n"); exit(0);}
      count++;
    }

    else if(!strcmp(argv[count], "-rank-type"))
    {
      printf("%s",argv[count]);
      count++;
      printf("%s",argv[count]);
      if(count == argc) {printf("Not enough parameters\n"); exit(0);}
      //Baselines
      else if(!strcmp(argv[count], "globalBase" ))  ranking = RANKING_GLOBAL_BASE;
      else if(!strcmp(argv[count], "globalStatic" ))  ranking = RANKING_GLOBAL_STATIC_PREDEFINED;
      else if(!strcmp(argv[count], "globalOF" ))  ranking = RANKING_GLOBAL_OLD;
      else if(!strcmp(argv[count], "globalOS" ))  ranking = RANKING_GLOBAL_OS_PRIORITY;
      //Random, RR 
      else if(!strcmp(argv[count], "globalRR" ))  ranking = RANKING_GLOBAL_STATIC_RR;
      else if(!strcmp(argv[count], "globalPA" ))  ranking = RANKING_GLOBAL_PROX_AWARE;
      else if(!strcmp(argv[count], "globalRD" ))  ranking = RANKING_GLOBAL_RANDOM;
      //SJF types
      //else if(!strcmp(argv[count], "globalStallSJF" ))  ranking = RANKING_GLOBAL_ROB_SJF;
      else if(!strcmp(argv[count], "globalRobSJF" ))  ranking = RANKING_GLOBAL_ROB_SJF;
      else if(!strcmp(argv[count], "globalInstSJF" ))  ranking = RANKING_GLOBAL_INSTR_SJF;
      else if(!strcmp(argv[count], "globalNast" ))  ranking = RANKING_GLOBAL_NAST_PRIORITY;
      else if(!strcmp(argv[count], "globalHybrid" ))  ranking = RANKING_GLOBAL_HYBRID_INST_NAST;
      else if(!strcmp(argv[count], "globalSTC" ))  ranking = RANKING_GLOBAL_STALL_CRITICAL;
      //Fairness
      else if(!strcmp(argv[count], "globalStallFair" ))  ranking = RANKING_GLOBAL_STALL_FAIRNESS;
      else if(!strcmp(argv[count], "globalFairOracle" ))  ranking = RANKING_GLOBAL_STALL_FAIRNESS_ORACLE;
      //Local
      else if(!strcmp(argv[count], "localRR" ))  ranking = RANKING_LOCAL_STATIC_RR;
      else if(!strcmp(argv[count], "localPA" ))  ranking = RANKING_LOCAL_PROX_AWARE;
      else if(!strcmp(argv[count], "localRD" ))  ranking = RANKING_LOCAL_RANDOM;
      else if(!strcmp(argv[count], "localSJF" ))  ranking = RANKING_LOCAL_SJF;
      else if(!strcmp(argv[count], "localOF" ))  ranking = RANKING_LOCAL_OLD;
      else if(!strcmp(argv[count], "localBase" ))  ranking = RANKING_LOCAL_BASE;
      else   {printf("Invalid ranking.\n"); exit(0);}
      count++;
    }
    else if(!strcmp(argv[count], "-batch-type"))
    {
      printf("%s",argv[count]);
      count++;
      printf("%s",argv[count]);
      if(count == argc) {printf("Not enough parameters\n"); exit(0);}
      else if(!strcmp(argv[count], "globalTB" ))  batching = BATCHING_GLOBAL_TIMEBASED;
      else if(!strcmp(argv[count], "globalRB" ))  batching = BATCHING_GLOBAL_REQBASED;
      else if(!strcmp(argv[count], "globalPB" ))  batching = BATCHING_GLOBAL_PACKETBASED;
      else if(!strcmp(argv[count], "globalFB" ))  batching = BATCHING_GLOBAL_FULLBATCHING;
      else if(!strcmp(argv[count], "globalTimeFB" ))  batching = BATCHING_GLOBAL_TB_FULLBATCHING;
      else if(!strcmp(argv[count], "localTB" ))  batching = BATCHING_LOCAL_TIMEBASED;
      else if(!strcmp(argv[count], "localRB" ))  batching = BATCHING_LOCAL_REQBASED;
      else if(!strcmp(argv[count], "localFB" ))  batching = BATCHING_LOCAL_FULLBATCHING;
      else if(!strcmp(argv[count], "rankOnly" ))  batching = BATCHING_RANKING_ONLY;
      else   {printf("Invalid batching type.\n"); exit(0);}
      count++;
    }

    else if(!strcmp(argv[count], "-slack-lat"))
    {
      printf("%s",argv[count]);
      count++;
      slack_per_hop_latency = atoi(argv[count]);
      printf("%s",argv[count]);
      count++;
    }

    else if(!strcmp(argv[count], "-batch-cap"))
    {
      printf("%s",argv[count]);
      count++;
      batch_cap = atoi(argv[count]);
      printf("%s",argv[count]);
      count++;
    }

    else if(!strcmp(argv[count], "-batch-int"))
    {
      printf("%s",argv[count]);
      count++;
      batch_int = atol(argv[count]);
      printf("%s",argv[count]);
      count++;
    }
    else if(!strcmp(argv[count], "-batch-levels"))
    {
      printf("%s",argv[count]);
      count++;
      MAX_BATCH_ID = atoi(argv[count]);
      printf("%s",argv[count]);
      count++;
    }

    else if(!strcmp(argv[count], "-rank-int"))
    {
      printf("%s",argv[count]);
      count++;
      rank_int = atol(argv[count]);
      printf("%s",argv[count]);
      count++;
    }
    else if(!strcmp(argv[count], "-rank-levels"))
    {
      printf("%s",argv[count]);
      count++;
      rank_levels = atoi(argv[count]);
      printf("%s",argv[count]);
      count++;
    }

    else if(!strcmp(argv[count], "-nuca"))
    {
      printf("%s",argv[count]);
      RESP_RQ_TRAFFIC = 1;
      count++;
    }

    else if(!strcmp(argv[count], "-n2"))
    {
      printf("%s",argv[count]);
      two_networks = YES;
      count++;
    }


    else if(!strcmp(argv[count], "-xshare"))
    {
      printf("%s",argv[count]);
      xshare = YES;
      count++;
    }

    else if(!strcmp(argv[count], "-max-msgs"))
    {
      printf("%s",argv[count]);
      count++;
      MSG_TO_INJECT = atol(argv[count]);
      WARMUP_MSG = 1000 < MSG_TO_INJECT ? 100 : 500;
      MSG_TO_EJECT = MSG_TO_INJECT - WARMUP_MSG;
      printf("%s",argv[count]);
      count++;
    }
    else if(!strcmp(argv[count], "-stat"))
    {
      printf("%s",argv[count]);
      count++;
      nox_stat_interval = atol(argv[count]);
      printf("%s",argv[count]);
      count++;
    }

    else if(!strcmp(argv[count], "-rob-size"))
    {
      printf("%s",argv[count]);
      count++;
      ROB_SIZE = atoi(argv[count]);
      printf("%s",argv[count]);
      count++;
    }

    else if(!strcmp(argv[count], "-ntech"))
    {
      printf("%s",argv[count]);
      count++;
      technode = atoi(argv[count]);
      printf("%s",argv[count]);
      count++;
    }

    else if(!strcmp(argv[count], "-hs"))
    {
      printf("%s",argv[count]);
      count++;
      high_swing_factor = atof(argv[count]);
      printf("%s",argv[count]);
      count++;
    }




    else if(!strcmp(argv[count], "-hybrid"))
    {
      printf("%s",argv[count]);
      hybrid_topology = YES;
      count++;
      //hybrid mratio is the ratio of local msg len to global msglen.
      mratio = atof(argv[count]);
      printf("%s",argv[count]);
      count++;
    }

    else if(!strcmp(argv[count], "-sm"))
    {
      printf("%s",argv[count]);
      count++;
      short_flit_ratio = atof(argv[count]);
      printf("%s",argv[count]);
      count++;
    }

    else if(!strcmp(argv[count], "-non-atomic"))
    {
      printf("%s",argv[count]);
      count++;
      ATOMIC_BUFFER=0;
    }

    else if(!strcmp(argv[count], "-atomic"))
    {
      printf("%s",argv[count]);
      count++;
      ATOMIC_BUFFER=1;
    }


    else if(!strcmp(argv[count], "-cdegree"))
    {
      printf("%s",argv[count]);
      count++;
      printf("%s",argv[count]);
      concentrated = YES;
      concentration_degree = atoi(argv[count]);
      count++;

    }

    else if(!strcmp(argv[count], "-link2"))
    {
      printf("%s",argv[count]);
      count++;
      printf("%s",argv[count]);
      link2 = atoi(argv[count]);
      count++;
    }

    else if(!strcmp(argv[count], "-balanced"))
    {
      printf("%s",argv[count]);
      count++;
      balanced_edge = YES;
    }



    else if(!strcmp(argv[count], "-ary"))
    {
      printf("%s",argv[count]);
      count++;
      printf("%s",argv[count]);
      bfly.k = atoi(argv[count]);
      count++;

    }

    else if(!strcmp(argv[count], "-fly"))
    {
      printf("%s",argv[count]);
      count++;
      printf("%s",argv[count]);
      bfly.n = atoi(argv[count]);
      count++;

    }

    // Number of virtual Channels
    else if(!strcmp(argv[count], "-nvc"))
    {
      printf("%s",argv[count]);
      count++;
      printf("%s",argv[count]);
      NUM_VC = atoi(argv[count]);
      count++;

    }

    // Number of flits per data message
    else if(!strcmp(argv[count], "-mlen"))
    {
      printf("%s",argv[count]);
      count++;
      printf("%s",argv[count]);
      MSG_LEN = atoi(argv[count]);
      count++;

    }

    else if(!strcmp(argv[count], "-fsize"))
    {
      printf("%s",argv[count]);
      count++;
      printf("%s",argv[count]);
      FLIT_WIDTH = atoi(argv[count]);
      count++;

    }

    else if(!strcmp(argv[count], "-psize"))
    {
      printf("%s",argv[count]);
      count++;
      printf("%s",argv[count]);
      CLINE_SIZE_BITS = atoi(argv[count]);
      count++;

    }


    else if(!strcmp(argv[count], "-bd"))
    {
      printf("%s",argv[count]);
      count++;
      printf("%s",argv[count]);
      router_inp_buf_size = atoi(argv[count]);
      count++;
      buffer_depth_not_defined=false;

    }

    else if(!strcmp(argv[count], "-num-PE"))
    {
      printf("%s",argv[count]);
      count++;
      printf("%s",argv[count]);
      NUM_PE = atoi(argv[count]);
      count++;
    }

    // NR represents number of rows in the tiled chip
    else if(!strcmp(argv[count], "-nr"))
    {
      printf("%s",argv[count]);
      count++;
      printf("%s",argv[count]);
      if(count == argc) {printf("Not enough parameters\n"); exit(0);}
      else
      {
        NUM_ROWS = atoi(argv[count]);

      }
      count++;
    }

    // NC represents number of columns in the tiled chip
    else if(!strcmp(argv[count], "-nc"))
    {
      printf("%s",argv[count]);
      count++;
      printf("%s",argv[count]);
      if(count == argc) {printf("Not enough parameters\n"); exit(0);}
      else
      {
        NUM_COLS = atoi(argv[count]);

      }
      count++;
    }				    

    // L represents 'Load Rate'
    else if(!strcmp(argv[count], "-l"))
    {
      printf("%s",argv[count]);
      count++;
      printf("%s",argv[count]);
      if(count == argc) {printf("Not enough parameters\n"); exit(0);}
      else
      {
        float rate = atof(argv[count]);

        if( 0.0 < rate && rate <= 1.0 ) 
          load_rate = rate;
        else { printf("Invalid load rate range. Should be between 0.0 and 1.0\n"); exit(0);}
      }
      count++;
    }		 

    else if(!strcmp(argv[count], "-active-source"))
    {
      printf("%s",argv[count]);
      count++;
      printf("%s",argv[count]);
      if(count == argc) {printf("Not enough parameters\n"); exit(0);}
      else
        active_source = atoi(argv[count]);
      count++;
    }


    // L represents 'Load Rate'
    else if(!strcmp(argv[count], "-bursty-nodes"))
    {
      printf("%s",argv[count]);
      count++;
      if(count == argc) {printf("Not enough parameters\n"); exit(0);}
      printf("%s",argv[count]);

      int bn = atoi(argv[count]); 
      for(int i=0; i<bn; i++)
      {
        count++;
        if(count == argc) {printf("Not enough parameters\n"); exit(0);}
        printf("%s",argv[count]);
        bursty_nodes[atoi(argv[count])]=1;
      }
      count++;
    }

    else if(!strcmp(argv[count], "-bursty-rate"))
    {
      printf("%s",argv[count]);
      count++;
      printf("%s",argv[count]);
      if(count == argc) {printf("Not enough parameters\n"); exit(0);}
      else
      {
        float rate = atof(argv[count]);

        if( 0.0 < rate && rate <= 1.0 ) 
          bursty_rate = rate;
        else { printf("Invalid bursty rate. Should be between 0.0 and 1.0\n"); exit(0);}
      }
      count++;
    }		

    // ELINK represents 'Link Error Rate'
    else if(!strcmp(argv[count], "-elink"))
    {
      printf("%s",argv[count]);
      count++;
      printf("%s",argv[count]);
      if(count == argc) {printf("Not enough parameters\n"); exit(0);}
      else
      {
        float rate = atof(argv[count]);

        if( 0.0 <= rate && rate <= 0.5 ) 
          link_err_rate = rate;
        else { printf("Invalid error rate range. Should be between 0.0 and 0.5\n"); exit(0);}
      }
      count++;
    }		    
    // EROUTER represents 'Routing Error Rate'
    else if(!strcmp(argv[count], "-eroute"))
    {
      printf("%s",argv[count]);
      count++;
      printf("%s",argv[count]);
      if(count == argc) {printf("Not enough parameters\n"); exit(0);}
      else
      {
        float rate = atof(argv[count]);

        if( 0.0 <= rate && rate <= 0.5 ) 
          routing_err_rate = rate;
        else { printf("Invalid error rate range. Should be between 0.0 and 0.5\n"); exit(0);}
      }
      count++;
    }		    
    // ESWARB represents 'Switch Arbiter Error Rate'
    else if(!strcmp(argv[count], "-eswarb"))
    {
      printf("%s",argv[count]);
      count++;
      printf("%s",argv[count]);
      if(count == argc) {printf("Not enough parameters\n"); exit(0);}
      else
      {
        float rate = atof(argv[count]);

        if( 0.0 <= rate && rate <= 0.5 ) 
          swarbiter_err_rate = rate;
        else { printf("Invalid error rate range. Should be between 0.0 and 0.5\n"); exit(0);}
      }
      count++;
    }		    

    // FN represents 'Number of Failed Node'
    else if(!strcmp(argv[count], "-fn"))
    {
      printf("%s",argv[count]);
      count++;
      printf("%s",argv[count]);
      if(count == argc) {printf("Not enough parameters\n"); exit(0);}
      else
      {
        int nf_node = (int)atof(argv[count]);

        if( nf_node <= 25 ) 
          num_failed_node = nf_node;
        else { printf("We recommend the number of failed node to be less than 25.\n"); exit(0);}
      }
      count++;
    }		    

    // FL represents 'Number of Failed Link'
    else if(!strcmp(argv[count], "-fl"))
    {
      printf("%s",argv[count]);
      count++;
      printf("%s",argv[count]);
      if(count == argc) {printf("Not enough parameters\n"); exit(0);}
      else
      {
        int nf_link = (int)atof(argv[count]);

        if( nf_link <= 25 ) 
          num_failed_link = nf_link;
        else { printf("We recommend the number of failed link to be less than 25.\n"); exit(0);}
      }
      count++;
    }		    

    // S represents 'Soft error retransmission'
    else if(!strcmp(argv[count], "-s"))
    {
      printf("%s",argv[count]);
      count++;
      printf("%s",argv[count]);
      if(count == argc) {printf("Not enough parameters\n"); exit(0);}
      else if(!strcmp(argv[count], "FEC"  )) retrans_type = FEC;
      else if(!strcmp(argv[count], "HFEC" )) retrans_type = HFEC;
      else if(!strcmp(argv[count], "E2E"  )) retrans_type = E2E;
      else if(!strcmp(argv[count], "HE2E" )) retrans_type = HE2E;
      else if(!strcmp(argv[count], "HBH"  )) retrans_type = HBH;
      else if(!strcmp(argv[count], "NONE" )) retrans_type = NONE;
      else   {printf("Invalid retransmission policy.\n"); exit(0);}
      count++;
    }		    

    // P represents 'Traffic Pattern'
    else if(!strcmp(argv[count], "-p"))
    {
      printf("%s",argv[count]);
      count++;
      printf("%s",argv[count]);
      if(count == argc) {printf("Not enough parameters\n"); exit(0);}
      else if(!strcmp(argv[count], "NR")) pattern = NR;
      else if(!strcmp(argv[count], "TP")) pattern = TP;
      else if(!strcmp(argv[count], "TN")) pattern = TN;
      else if(!strcmp(argv[count], "BC")) pattern = BC;
      else if(!strcmp(argv[count], "NB")) pattern = NB;
      else if(!strcmp(argv[count], "LC")) 
      {
        pattern = LC;
        count++;
        printf("%s",argv[count]);
        local_traffic_ratio = atof(argv[count]);
        count++;
      }
      else if(!strcmp(argv[count], "HT")) pattern = HT;
      else   {printf("Invalid traffic pattern.\n"); exit(0);}
      count++;
    }
    // P represents 'Traffic Pattern'
    else if(!strcmp(argv[count], "-traffic-mix"))
    {
      printf("%s",argv[count]);
      count++;
      printf("%s",argv[count]);
      if(count == argc) {printf("Not enough parameters\n"); exit(0);}
      cluster_rows = atoi(argv[count]);

      count++;
      printf("%s",argv[count]);
      if(count == argc) {printf("Not enough parameters\n"); exit(0);}
      cluster_cols = atoi(argv[count]);


      num_patterns = (NUM_COLS/cluster_cols) * (NUM_ROWS/cluster_rows);
      //num_patterns = atoi(argv[count]);

      for(int i=0; i<num_patterns; i++)
      {
        count++;
        if(!strcmp(argv[count], "NR")) mix_pattern[i] = NR;
        else if(!strcmp(argv[count], "TP")) mix_pattern[i] = TP;
        else if(!strcmp(argv[count], "TN")) mix_pattern[i] = TN;
        else if(!strcmp(argv[count], "BC")) mix_pattern[i] = BC;
        else if(!strcmp(argv[count], "NB")) mix_pattern[i] = NB;
        else if(!strcmp(argv[count], "HT")) mix_pattern[i] = HT;
        else {printf("Invalid traffic pattern.\n"); exit(0);}
      }
      count++;
    }			    

    // A represents 'Router Architecture'. Either 2 or 3 stage.
    else if(!strcmp(argv[count], "-a"))
    {
      printf("%s",argv[count]);
      count++;
      printf("%s",argv[count]);
      if(count == argc) {printf("Not enough parameters\n"); exit(0);}
      else if(!strcmp(argv[count], "1")) arch = 1;
      else if(!strcmp(argv[count], "2")) arch = 2;
      else if(!strcmp(argv[count], "3")) arch = 3;
      else if(!strcmp(argv[count], "4")) arch = 4;
      else   {printf("Invalid router architecture.\n"); exit(0);}
      count++;
    }	

    // i represents 'Input Traffic'. 
    else if(!strcmp(argv[count], "-i"))
    {
      printf("%s",argv[count]);
      count++;
      printf("%s",argv[count]);
      if(count == argc) {printf("Not enough parameters\n"); exit(0);}
      else if(!strcmp(argv[count], "UNIFORM")) in_traffic = UNIFORM;
      else if(!strcmp(argv[count], "MULTI")) in_traffic = MULTIMEDIA;
      else if(!strcmp(argv[count], "SSIM")) in_traffic = SSIMILAR;
      else   {printf("Invalid input traffic.\n"); exit(0);}
      count++;
    }	

    else if(!strcmp(argv[count], "-v"))
    {
      printf("%s",argv[count]);
      count++;
      verbose = YES;
    }

    else if(!strcmp(argv[count], "-source-queue"))
    {
      printf("%s",argv[count]);
      source_queue_logic_enabled=true;
      count++;
    }


    else if(!strcmp(argv[count], "-trace"))
    {
      printf("%s",argv[count]);
      count++;
      synthetic_trace_enabled=1;
    }		 		    

    else if(!strcmp(argv[count], "-q"))
    {
      printf("%s",argv[count]);
      count++;
      sql = YES;
    }		    

    // QF represents 'SQL file name'
    else if(!strcmp(argv[count], "-qf"))
    {
      printf("%s",argv[count]);
      count++;
      printf("%s",argv[count]);
      if(count == argc) {printf("Not enough parameters\n"); exit(0);}
      else if(sizeof(argv[count]) > 40)
      {
        printf("Filename too long (should be less than 40 characters)\n"); 
        exit(0);
      }
      else
      {
        strcpy(sql_fn, argv[count]);
        count++;
      }
    }		    

    else if(!strcmp(argv[count], "-j"))
    {
      printf("%s",argv[count]);
      count++;
      early_ejection = YES;
    }		    

    else
    { 
      printf("Invalid option %s\n",argv[count]); 
      exit(0);
    }
  }// while

  if(sql == YES)
  {
    if(sql_fn == NULL)
    {
      printf("Filename for SQL is not specified. Add '-qf SQL_filename'.\n"); 
      exit(0);
    }

    // Open file for SQL output
    if( (fsql = fopen(sql_fn,"w") ) == NULL )
    {
      fprintf(stderr, "Cannot open file for SQL output");
      exit(1);
    }

    // Initialize database
    if(sql == YES)
      fprintf(fsql, "DELETE FROM FLIT;\nDELETE FROM FLOW;\n");
  }


#ifdef TR_INTEG
  CLINE_SIZE_BITS = llc_linesize*8;
  MSG_LEN = (int)(ceil(CLINE_SIZE_BITS / (double)FLIT_WIDTH));
  if(buffer_depth_not_defined)
    router_inp_buf_size = MSG_LEN+1 > 8 ? MSG_LEN+1:8;
#else
  if(!MSG_LEN)
    MSG_LEN = (int)(ceil(CLINE_SIZE_BITS / (double)FLIT_WIDTH));
  if(buffer_depth_not_defined)
    router_inp_buf_size = max(2*MSG_LEN, 8);
#endif


  /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
  //  Intialize topology specific information
  /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
  if(topology == XBAR)
  {
    NUM_NIC_PC = NUM_PE;
    NUM_PC = NUM_PE;
    NUM_NODES = 1;
    NUM_ROWS = 1;
    NUM_COLS = 1;
    router_info[0].num_pc     = NUM_PC;
    router_info[0].num_nic_pc = NUM_NIC_PC;
    router_info[0].num_vc     = NUM_VC;
    router_info[0].type      = FLAT;
    //mulitplication factor to basic tile energy used in mesh
    link_length = 1;
  }

  if(topology == BUS)
  {
    NUM_NIC_PC = NUM_PE;
    NUM_PC = NUM_PE;
    NUM_NODES = 1;
    NUM_ROWS = 1;
    NUM_COLS = 1;
    router_info[0].num_pc     = NUM_PC;
    router_info[0].num_nic_pc = NUM_NIC_PC;
    router_info[0].num_vc     = NUM_VC;
    router_info[0].type      = FLAT;
    node_switch[0]           = BUS_SWITCH;
    //mulitplication factor to basic tile energy used in mesh
    link_length = NUM_PE/2;
  }

  if(topology == FTREE && hybrid_topology == NO)
  {
    //Currently we support just two level, one root node and leaves which are
    //high radix routers
    NUM_NIC_PC = concentration_degree;
    NUM_NODES = NUM_PE/concentration_degree == 1 ? 1 : NUM_PE/concentration_degree + 1;
    NUM_PC    = concentration_degree + 1;
    NUM_ROWS  = 1;
    NUM_COLS  = NUM_NODES;

    //mulitplication factor to basic tile energy used in mesh
    link_length = 1;
    link2 = 1;

    for(int node = 0; node < NUM_NODES; node++)
    {
      router_info[node].num_pc     = NUM_PC;
      router_info[node].num_nic_pc = NUM_NIC_PC;
      router_info[node].num_vc     = NUM_VC;
      router_info[node].type       = FLAT;
      if(node == NUM_NODES-1 && NUM_NODES != 1)
      {
        router_info[node].num_pc     = 4;
        router_info[node].num_nic_pc = 0;
        router_info[node].num_vc     = NUM_VC;
        router_info[node].type       = FLAT;
      }
      for(int pc= 0; pc < NUM_PC-NUM_NIC_PC; pc++)
        link_info[node][pc] = link2;
    }
  }


  if(topology == BFLY)
  {
    NUM_NIC_PC = bfly.k;
    NUM_PC = (bfly.n-1)*(bfly.k-1)+bfly.k;
    NUM_ROWS = bfly.k;
    NUM_COLS = bfly.k;
    NUM_NODES = (int)pow(bfly.k, bfly.n-1);
    NUM_PE = NUM_NODES*bfly.k;

    //mulitplication factor to basic tile energy used in mesh
    link_length = ceil(bfly.k/2.0)*(bfly.k/2.0);
    //mulitplication factor to basic tile energy used in mesh
    if(NUM_PE > 128)
      link_length = 12;

    //FIXME by default two cycle links are used in CMESH
    link2 = 1;
    if(NUM_PE >= 64)
      link2 = 2;
    if(NUM_PE >= 128)
      link2 = 3;


    for(int node = 0; node < NUM_NODES; node++)
    {
      router_info[node].num_pc     = NUM_PC;
      router_info[node].num_nic_pc = NUM_NIC_PC;
      router_info[node].num_vc     = NUM_VC;
      router_info[node].type       = FLAT;
      for(int pc= 0; pc < NUM_PC-NUM_NIC_PC; pc++)
        link_info[node][pc] = link2;
    }
  }

  if((topology == MESH || topology == TORUS) && hybrid_topology == NO)
  {
    if( NUM_ROWS > MAX_ROWS ) 
    { printf("Invalid num rows, exceeds max num rows %d\n", MAX_ROWS); exit(0);}
    if( NUM_COLS > MAX_COLS ) 
    { printf("Invalid num rows, exceeds max num rows %d\n", MAX_COLS); exit(0);}

    NUM_NODES = NUM_ROWS * NUM_COLS;
    concentration_degree = NUM_PE / NUM_NODES;
    if(concentration_degree > 1)
      concentrated = YES;

    NUM_PC = 4 + concentration_degree;
    NUM_NIC_PC = concentration_degree;

    link2 = 0;

    for(int node = 0; node < NUM_NODES; node++)
    {
      router_info[node].num_pc     = NUM_PC;
      router_info[node].num_nic_pc = NUM_NIC_PC;
      router_info[node].num_vc     = NUM_VC;
      router_info[node].type       = FLAT;
      for(int pc= 0; pc < NUM_PC-NUM_NIC_PC; pc++)
        link_info[node][pc] = link2;
    }
    //mulitplication factor to basic tile energy used in mesh
    link_length = concentration_degree > 1 ? concentration_degree/2 : 1;
  }

  if((topology == MESH || topology == TORUS) && hybrid_topology == YES)
  {
    int local_routers = NUM_PE/concentration_degree;
    int global_routers = NUM_ROWS*NUM_COLS;

    NUM_NODES = local_routers + global_routers;

    //make this two if you want to hold the bus for two cycles
    //multi_cycle_SA = 1;

    //mulitplication factor to basic tile energy used in mesh
    link_length = 1;
    if(NUM_PE >= 64)
      link_length = 3;

    if(NUM_PE >= 64)
      link2 = 1;

    for(int node = 0; node < local_routers; node++)
    {
      router_info[node].num_pc     = NUM_PC     = 2 + concentration_degree;
      router_info[node].num_nic_pc = NUM_NIC_PC = concentration_degree;
      router_info[node].num_vc     = NUM_VC;
      router_info[node].type       = LOCAL;
      node_switch[node]            = BUS_SWITCH;

      for(int pc= 0; pc < NUM_PC-NUM_NIC_PC; pc++)
        link_info[node][pc] = 0;
    }

    for(int node = local_routers ; node < NUM_NODES; node++)
    {
      router_info[node].num_pc     = NUM_PC     = 5;
      router_info[node].num_nic_pc = NUM_NIC_PC = 0;
      router_info[node].num_vc     = NUM_VC;
      router_info[node].type       = GLOBAL;

      for(int pc= 0; pc < NUM_PC-NUM_NIC_PC; pc++)
      {
        if(pc == EAST || pc == WEST)
          link_info[node][pc] = link2;
        else
          link_info[node][pc] = 0;
      }
    }
  }
  if(topology == FTREE && hybrid_topology == YES)
  {
    int local_routers = NUM_PE/concentration_degree;
    //Assuming same concentration_degree for local and global network
    int global_routers = local_routers/concentration_degree == 1 ? 1 : local_routers/concentration_degree + 1 ;

    NUM_NODES = local_routers + global_routers;

    //mulitplication factor to basic tile energy used in mesh
    link_length = 1;
    link2 = 0;

    for(int node = 0; node < local_routers; node++)
    {
      router_info[node].num_pc     = NUM_PC     = 2 + concentration_degree;
      router_info[node].num_nic_pc = NUM_NIC_PC = concentration_degree;
      router_info[node].num_vc     = NUM_VC;
      router_info[node].type       = LOCAL;
      node_switch[node]            = BUS_SWITCH;

      for(int pc= 0; pc < NUM_PC-NUM_NIC_PC; pc++)
        link_info[node][pc] = 0;
    }

    for(int node = local_routers ; node < NUM_NODES; node++)
    {
      router_info[node].num_pc     = NUM_PC     = 1 + concentration_degree;
      router_info[node].num_nic_pc = NUM_NIC_PC = 0;
      router_info[node].num_vc     = NUM_VC;
      router_info[node].type       = GLOBAL;
      if(node == NUM_NODES - 1 && global_routers != 1)
        router_info[node].num_pc   = NUM_PC     = 4;

      for(int pc= 0; pc < NUM_PC-NUM_NIC_PC; pc++)
        link_info[node][pc] = link2;
    }
  }


  printf("\nSetting num nodes:%d num PEs:%d num pc:%d nic pc:%d num vc:%d msg len:%d buf depth:%d cdegree:%d link_length:%.2f\n",
      NUM_NODES,NUM_PE,NUM_PC,NUM_NIC_PC,NUM_VC,MSG_LEN,router_inp_buf_size,concentration_degree, link_length);

  /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
  // Initialize has_flit flag.
  /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
  for(node=0; node<NUM_NODES; node++)
  {
    NUM_PC     = router_info[node].num_pc;
    NUM_NIC_PC = router_info[node].num_nic_pc;
    NUM_VC     = router_info[node].num_vc;
    for(pc=0; pc<NUM_PC; pc++)
      for(vc=0; vc<NUM_VC; vc++)
      {
        has_flit[node][pc][vc].arbiter = NO;
        has_flit[node][pc][vc].xbar    = NO;
      }
  }

  /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
  //  Intialize layout specific information
  /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
#ifdef TR_INTEG
  int cpu=0,cache=0;
  int cd = concentration_degree;
  if(topology == BFLY)
    cd = bfly.k;
  for(int i = 0; i< 128; i++)
  {
    cpu_network_layout[i] = -1;
    cache_network_layout[i] = -1;
    inverse_cache_network_layout[i] = -1;
    inverse_cpu_network_layout[i] = -1;
  }

  /*
  Commented byNachi.
  if(NUM_PE != numcpus + num_llc_banks)
  {
    printf("ERR CMP network size not maching NoX configuration!! nox nodes:%d cmp nodes:%d\n",NUM_PE,numcpus+num_llc_banks);
    //exit(1);
  }*/

  if(cd == 1)
  {
    if(NUM_ROWS == 1)
    {
      for(int i = 0; i< NUM_COLS; i++)
      {
        if(cpu < numcpus)
        {
          inverse_cpu_network_layout[i] = cpu;
          cpu_network_layout[cpu++] = i;
        }
        else
        {
          inverse_cache_network_layout[i] = cache;
          cache_network_layout[cache++] = i;
        }
      }
    }
    else
    {
      //MESH top and bottom rows are cores 
      int rows_with_cpu = numcpus/NUM_COLS;
      for(int i = 0; i< NUM_ROWS; i++)
        for(int j = 0; j< NUM_COLS; j++)
        {
          if((i<rows_with_cpu/2 || i>= NUM_ROWS-rows_with_cpu/2) && cpu < numcpus )
          {
            inverse_cpu_network_layout[i*NUM_COLS +j] = cpu;
            cpu_network_layout[cpu++] = i*NUM_COLS + j;
            //if(verbose == YES)
            //  printf("cpu   :%d network node:%3d\n",cpu-1,cpu_network_layout[cpu-1]);
          }
          else
          {
            inverse_cache_network_layout[i*NUM_COLS +j] = cache;
            cache_network_layout[cache++] = i*NUM_COLS + j;
            //if(verbose == YES)
            //  printf("cache :%d network node:%3d\n",cache-1,cache_network_layout[cache-1]);
          }
        }
      for(int i = 0; i< num_mem_controllers/2; i++)
      {
        mem_network_layout[i] = i;
        mem_network_layout[num_mem_controllers - i - 1] = numcpus + num_llc_banks - i - 1;
      }
      
      if(verbose == YES)
        for(int i = 0; i< num_mem_controllers; i++)
          printf("mem contoller:%d nnode:%d\n",i,mem_network_layout[i]);
    }
  }
  else //cd != 1
  {
    //equal number of processor and cache tiles in each cluster
    int cores_per_cluster = cd/2;
    int caches_per_cluster = cd/2;
    for(int i=0; i<NUM_PE/cd; i++)
    {
      if(i < num_mem_controllers)
        mem_network_layout[i] = i*cd;
      for(int j=0; j < cd ; j++)
      {
        if(j < cores_per_cluster && cpu < numcpus)
        {
          inverse_cpu_network_layout[i*cd+j] = cpu;
          cpu_network_layout[cpu++] = i*cd + j;
          //if(verbose == YES)
          //  printf("cpu   :%d network node:%d\n",cpu-1,cpu_network_layout[cpu-1]);
        }
        else
        {
          inverse_cache_network_layout[i*cd+j] = cache;
          cache_network_layout[cache++] = i*cd + j;
          //if(verbose == YES)
          //  printf("cache :%d network node:%d\n",cache-1,cache_network_layout[cache-1]);
        }
      }
    }
    if(verbose == YES)
      for(int i = 0; i< num_mem_controllers; i++)
        printf("mem contoller:%d nnode:%d\n",i,mem_network_layout[i]);
  }

  //FIXME this works only if number of processor tile is equal to number of
  //cache tiles
  if(bank_map == MEM_PAGE_INTERLEAVING)
  {
    //printf("proximity vector\n");
    for(int i = 0; i< numcpus; i++)
    {
      //printf("procID%d :",i);
      for(int j = 0; j< num_llc_banks; j++)
      {
        bank_proximity[i][j]=(i+j)%num_llc_banks;
        //printf("%d ",bank_proximity[i][j]);
      }
      //printf("\n");
    }
  }
  
  if(num_mem_controllers == 1)
    mem_network_layout[0] = NUM_NODES/2;

  //Few of the above computations are overridden here
  //FIXME making 64 node CMP with no concentration
  cpu = 0; cache = 0;
  for(int i = 0; i< NUM_ROWS; i++)
    for(int j = 0; j< NUM_COLS; j++)
    {
      inverse_cpu_network_layout[i*NUM_COLS +j] = cpu;
      cpu_network_layout[cpu++] = i*NUM_COLS + j;
      //if(verbose == YES)
      //  printf("cpu   :%d network node:%3d\n",cpu-1,cpu_network_layout[cpu-1]);
      inverse_cache_network_layout[i*NUM_COLS +j] = cache;
      cache_network_layout[cache++] = i*NUM_COLS + j;
      //if(verbose == YES)
      //  printf("cache :%d network node:%3d\n",cache-1,cache_network_layout[cache-1]);

    }

  //Few of the above computations are overridden here
  num_mem_controllers = 4;
  mem_network_layout[0] = 0;
  mem_network_layout[1] = NUM_COLS-1;
  mem_network_layout[2] = NUM_NODES - NUM_COLS;
  mem_network_layout[3] = NUM_NODES - 1;
  
  for(int i = 0; i< num_mem_controllers; i++)
    printf("mem contoller:%d nnode:%d\n",i,mem_network_layout[i]);
  
  if(cpu != numcpus || cache != num_llc_banks)
  {
    printf("Layout not complete!!! cpu :%d cache: %d numcpus: %d num_llc_banks: %d cd:%d\n",
        cpu, cache, numcpus, num_llc_banks,cd);
    exit(1);
  }
#endif

  /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
  //  Intialize Topology Connections
  /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
  node_init(); // defined in node_init.h/c
  health_init();

  /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
  //  Intialize Power specific information
  /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/


  if(NUM_PE <= 16)
    technology_node = 70;
  else if(NUM_PE <= 32)
    technology_node = 50;
  else if(NUM_PE <= 64)
    technology_node = 35;
  else if(NUM_PE <= 128)
    technology_node = 22;
  else if(NUM_PE <= 256)
    technology_node = 16;
  
  if(technode != -1)
    technology_node = technode;

  if(hybrid_topology == YES)
    BUS_WIDTH=(int)(FLIT_WIDTH/mratio);
  if(topology == BUS)
    BUS_WIDTH = FLIT_WIDTH;

  FILE *fp_pow = fopen("power-config", "r");
  if(fp_pow == NULL)
  {
    printf("ERR ! cannot open the file specifing the power numbers for xbar and buffer!\n");
    exit(1);
  }

  node = 0;

  char buffer[100];
  bool router_config_found = false, bus_config_found=true;
  float buff, xbar, link1b, p_1_arb, pv_1_arb, v_1_arb, bus_link1b, bus_overhead, leakage;
  int fz=0, npc=0, tn=45;
  int radix, bus_radix;

  radix = router_info[0].num_pc;

  //just skip power for bus and xbar they are only of theoretical
  //interest
  if(topology == BUS || topology == XBAR)
    router_config_found=true;

  if(hybrid_topology == YES)
  {
    if(NUM_PE < 64)
      radix = 3;
    else
      //local routers 0...NUM_PE/concentration_degree-1
      //global router NUM_PE/concentration_degree ... NUM_NODES
      radix = router_info[NUM_PE/concentration_degree].num_pc;
    if(topology == FTREE)
      radix = 8;

    bus_config_found= false;
    bus_radix = router_info[0].num_nic_pc;
  }

  //Ring
  if(topology == TORUS && NUM_ROWS == 1)
    radix = 3;

  //Routing power
  PD_ROUTER = PD_ROUTER_CONSTANT;

  while(!feof(fp_pow))
  {
    fgets(buffer,100,fp_pow);
    sscanf(buffer,"%d\t%d\t%d\t%f\t%f\t%f\t%f\t%f\t%f\t%f\t%f\t%f\n", &tn, &npc, &fz, 
        &buff, &xbar, &link1b, &pv_1_arb, &p_1_arb, &v_1_arb, &bus_link1b,&leakage);

    if(fz == FLIT_WIDTH && npc == radix && tn == technology_node && router_config_found == false)
    {
      router_config_found = true; 
      //Buffer
      PD_BUFFER = buff;
      //Xbar
      PD_XBAR_F = xbar;
      //Link
      PD_LINK = FLIT_WIDTH * link1b * link_length * high_swing_factor;
      //Arbitration
      PD_P_1_ARB = p_1_arb;
      PD_PV_1_ARB = pv_1_arb;
      PD_V_1_ARB = v_1_arb;
      pl_static_energy = leakage;

    }
    if(npc == bus_radix && tn == technology_node && bus_config_found == false)
    {
      bus_config_found=true;
      PD_LINK_BUS = BUS_WIDTH*bus_link1b;//*0.75 + bus_overhead/BUS_WIDTH;
      pd_p_1_bus = p_1_arb;
      pd_pv_1_bus = pv_1_arb;
      pd_v_1_bus = v_1_arb;
    }
    if(bus_config_found && router_config_found)
      break;
  }


  if(!router_config_found || !bus_config_found)
  {
    printf("Power Config not found !! tech = %d P = %d W = %d defaulting to MESH at 45nm, 64 bit flit size\n", technology_node, radix, FLIT_WIDTH);
    //exit(1);
  }
  for(node=0; node<NUM_NODES; node++)
  {

    router_info[node].pd_p_1_arb = PD_P_1_ARB;
    router_info[node].pd_pv_1_arb = PD_PV_1_ARB;
    router_info[node].pd_v_1_arb = PD_V_1_ARB;

    router_info[node].pl_p_1_arb = PL_P_1_ARB;
    router_info[node].pl_pv_1_arb = PL_PV_1_ARB;
    router_info[node].pl_v_1_arb = PL_V_1_ARB;

    if(hybrid_topology == YES && node < NUM_PE/concentration_degree)
    {
      router_info[node].pd_p_1_arb = pd_p_1_bus;
      router_info[node].pd_pv_1_arb = pd_pv_1_bus;
      router_info[node].pd_v_1_arb = pd_v_1_bus;
    }
  }
  fclose(fp_pow);

  /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
  //  Hybrid parameter checking
  /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/

  if(hybrid_topology == YES && ((int)(MSG_LEN*mratio) == 0) ) 
  {
    printf("Invalid Hybrid msg ratio : %.2f, mlen : %d, local msg len should be greater than zero!\n",
        mratio, MSG_LEN);
    exit(1);
  }
  /*if(hybrid_topology == YES &&  (router_inp_buf_size < 2*MSG_LEN*(1-mratio)) ) 
    {
    printf("Invalid Hybrid buffer depth glen : %d, llen :%d , required depth:%d , current depth :%d\n",
    MSG_LEN, (int)(mratio*MSG_LEN), (int)(2*MSG_LEN*(1-mratio)), router_inp_buf_size);
    exit(1);
    }*/

  if(hybrid_topology  == YES)
    printf(" Hybrid config  local msg len : %d global msg len : %d\n", (int)(mratio*MSG_LEN), MSG_LEN);


  /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
  double rate;
  if(!bursty_rate)
    bursty_rate = load_rate;

  for(node=0; node<NUM_NODES; node++)
  {
    rate = bursty_nodes[node] ? bursty_rate : load_rate; 

    msgs_to_inject[node] = bursty_nodes[node] ? MSG_TO_INJECT : (int)(MSG_TO_INJECT*(load_rate/bursty_rate));
    warmup_msgs[node]    = bursty_nodes[node] ? WARMUP_MSG  :  (int)(WARMUP_MSG*(load_rate/bursty_rate));
    msgs_to_eject[node]  = msgs_to_inject[node] - warmup_msgs[node];
    OT_JOB_SIZE[node]    = bursty_nodes[node] ? 1/*(int)(ROB_SIZE * bursty_rate/load_rate)*/ : ROB_SIZE ;
    
    if(active_source  == -1)
      load_rate_per_source[node]= rate;
    else
    {
      load_rate_per_source[node]= node == active_source ? rate : 0;
    }
    source_base_throughput[node] = -1;
  }

  /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/

  if(source_queue_logic_enabled)
  {
    printf("Traffic Matrix \n");
    if(num_patterns > 0)
    {
      int t_rows = NUM_ROWS/cluster_rows;
      int t_cols = NUM_COLS/cluster_cols;

      for(int r=0; r < NUM_ROWS; r++)
      {
        for(int c=0; c < NUM_COLS; c++)
        {
          int row = r/cluster_rows;
          int col = c/cluster_cols;
          printf("patterns:%d node :%d cluster:%d\n",num_patterns,r*NUM_COLS + c,row*t_cols + col);
          pattern_per_source[r*NUM_COLS + c] = mix_pattern[row*t_cols + col];
          printf("[%s|%.2f] ",tp[pattern_per_source[r*NUM_COLS + c]],load_rate_per_source[r*NUM_COLS + c]); 
        }
        printf("\n");
      }

    }
    else
    {
      for(int r=0; r < NUM_ROWS; r++)
      {
        for(int c=0; c < NUM_COLS; c++)
        {
          pattern_per_source[r*NUM_COLS + c] = pattern;
          printf("[%s|%.2f] ",tp[pattern_per_source[r*NUM_COLS + c]],load_rate_per_source[r*NUM_COLS + c]); 
        }
        printf("\n");
      }
    }
  }
  else
  {
    for(node=0; node<NUM_NODES; node++)
      pattern_per_source[node] = pattern;
  }

  /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
  //Read traces synthetic
  /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/

  char name[64][30];
  gzFile zfp;
  if(synthetic_trace_enabled)
  {
    int dummy; 
    int dst;
    long long clk;
    for(node=0; node<NUM_NODES; node++)
    {
      if(active_source  == -1 || (active_source != -1 && node == active_source))
      {
        if(NUM_PE == 64)
          sprintf(name[node], "traces/64n-mesh/trace-%dn-%stp-%.2fl.gz",node,tp[pattern_per_source[node]],load_rate_per_source[node]);
        else
          sprintf(name[node], "traces/trace-%dn-%stp-%.2fl.gz",node,tp[pattern_per_source[node]],load_rate_per_source[node]);
        zfp = gzopen(name[node],"r");
        if(zfp == NULL)
        {
          printf("ERR opening trace file :%s\n",name[node]);
          exit(1);
        }
        else if(verbose == YES)
          printf("Reading trace %s\n",name[node]);
        int index = 0;
        char buff[40];
        while(!gzeof(zfp))
        {
          gzgets(zfp,buff,40);
          sscanf(buff,"%2d %2d %lld\n",&dummy,&dst, &clk);
          trace_buffer[node][index].dst = dst;
          trace_buffer[node][index].clock = clk;
          index++;
        } // while
      }// if
    }//for

    FILE *fp = fopen("table-single-source", "r");
    if(fp == NULL)
    {
      printf("ERR ! cannot open the file specifing the power numbers for xbar and buffer!\n");
      exit(1);
    }

    char buffer[100];
    int n,scan=0;
    double th,lat;
    float r;
    char w[10];
    node = 0;
    if(active_source != -1)
      node = active_source;

    if(active_source == -1)
    {
      while(scan <= NUM_NODES)
      {
        fgets(buffer,100,fp);
        sscanf(buffer,"%d %f %s %lf %lf\n", &n, &r, &w, &th, &lat);
        if(n == node && r == load_rate_per_source[node] && !strcmp(w,tp[pattern_per_source[node]]) )
        {
          source_base_throughput[node] = th;
          source_base_latency[node] = lat;
          node++;
          if(active_source != -1)
            break;

          if(node >= NUM_NODES)
            break;
        }
        if(verbose == YES)
          printf("node:%d/%d rate:%.2lf/%.2lf pattern:%s/%s | %s",node,n,load_rate_per_source[node],r, 
              tp[pattern_per_source[node]],w, buffer);
        if(feof(fp))
        {
          rewind(fp);
          scan++;
        }
      }
    }
    fclose(fp);
  }// if trace enabled

  /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
  //  Intialize batching specific information
  /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
  PRIORITY_VC_SET = NO;
  if(ARB_TYPE == PR)
  {
#ifdef TR_INTEG
    MAX_PRIORITY_LEVELS = numcpus;
    num_priority_levels = 8;
    if(rank_levels != -1)
    num_priority_levels = rank_levels;
#else
    MAX_PRIORITY_LEVELS = NUM_PE;
    num_priority_levels = 4;
#endif

    for(node=0; node<NUM_NODES; node++)
    {
      batching_mode[node]     = batching;
      ranking_type[node]      = ranking;
      marking_cap[node]       = batch_cap;
      batching_interval[node] = batch_int;
      ranking_interval[node]  = rank_int;
      for(int pri_level=0; pri_level<MAX_PRIORITY_LEVELS; pri_level++)
      {
        //global_priority_matrix[node][pri_level] = pri_level%num_priority_levels;
        //global_priority_matrix[node][pri_level] =  ranking_vector_HT[pri_level];
        global_priority_matrix[node][pri_level] =  ranking_vector_Static[pri_level];
        if(ranking == RANKING_GLOBAL_OS_PRIORITY)
        global_priority_matrix[node][pri_level] =  ranking_OS_Weights[pri_level];
      }
    }

		GlobalBatchMode = batching;
		GlobalBatchMarkingCap = batch_int;
		GlobalRankMode = ranking;
		GlobalRankInterval = rank_int;
    
    if(PRIORITY_VC_SET  == YES)
    {
      for(node=0; node<NUM_NODES; node++)
        router_info[node].num_vc     = num_priority_levels*NUM_VC;
      NUM_VC = num_priority_levels * NUM_VC;
    }

    //SPARE buffer logic for priority inversion
    if(age_based_arbitration == false)
    {
      for(node=0; node<NUM_NODES; node++)
        router_info[node].num_vc++; 
      NUM_VC++;
    }
  }

  /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
#ifdef TR_INTEG
  NUM_NIC_VC = numcpus;
#else
  NUM_NIC_VC = NUM_NIC_BASE_VC;
#endif


  /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
  if(routing_algorithm == PA)
  {
    init_FA_route_info();
    init_FA_neighbor_info();
    init_FA_direction_info();
  }

}
